﻿using System;

namespace StreamingClient.TSSplitter
{

   // Packetized Elementary Stream Header
   public class PESPacket
    {

        byte[] _packet;
        int PES_OFFSET;


       
        public PESPacket(byte[] packet, int offset)
        {
            _packet = packet;
            PES_OFFSET = offset;            
            if (offset > 4)
            {
                PES_OFFSET += 1;
            }

        }


        public int START_CODE_PREFIX
        {
            get
            {
                if (PES_OFFSET < _packet.Length - 2)
                {
                    return ((_packet[PES_OFFSET] << 16) | (_packet[PES_OFFSET + 1] << 8) | (_packet[PES_OFFSET + 2]));
                }
                else return 0;
            }
        }


        public int STREAM_ID
        {
            get
            {
                return (_packet[PES_OFFSET+3]);
            }
        }


        public int PACKET_LENGTH
        {
            get
            {
                return ((_packet[PES_OFFSET + 4] << 8) | _packet[PES_OFFSET + 5]);
            }
        }


        public bool IsVideoStream
        {
            get
            {
                return ((STREAM_ID>= 0xE0 ) && (STREAM_ID <= 0xEF));
            }
        }



        public bool IsAudioStream
        {
            get
            {
                return ((STREAM_ID>= 0xC0 ) && (STREAM_ID <= 0xDF));
            }
        }


       public bool HasExtension
        {
           get
            {
               return ((_packet[PES_OFFSET + 6] & 0x80) > 0);
            }
        }

        public bool IsScrambled
        {
            get
            {
                return ((_packet[PES_OFFSET+6] & 0x30) > 0);
            }
        }


        public bool HasPriority
        {
            get
            {
                return ((_packet[PES_OFFSET+6] & 0x8) > 0);
            }
        }


        public bool IsAligned
        {
            get
            {                
                return ((_packet[PES_OFFSET+6] & 0x4) > 0);;
            }
        }
    
        
        
        public bool HasPTS
        {
            get
            {
                return ((_packet[PES_OFFSET+7] & 0x80) == 0x80); 
            }
        }
        

       public bool HasDTS
        {
            get
            {
                return ((_packet[PES_OFFSET+7] & 0x40) == 0x40); 
            }
        }


       public int HEADER_DATA_LENGTH
       {
           get
           {
                int x = (_packet[PES_OFFSET+8]);
                if (x > MAX_PACKET_SIZE) return -1; 
                return x;
           }
       }

       public const int MAX_PACKET_SIZE = 204;
              
       public TimeSpan PTS
       {
           get
           {
                if ((START_CODE_PREFIX==1)&&(HasPTS))
                {
                    uint l = 0;
                    byte b1 = (byte) (_packet[PES_OFFSET+9] & 0xE);
                    byte b2 = (byte) (_packet[PES_OFFSET + 10]);
                    byte b3 = (byte) (_packet[PES_OFFSET + 11] & 0xFE);
                    byte b4 = (byte) (_packet[PES_OFFSET + 12]);
                    byte b5 = (byte)(_packet[PES_OFFSET + 13] & 0xFE);
                    l = (uint) ((b1 << 29) | (b2<<22) | (b3 << 14) | (b4 << 7) | (b5 >> 1));
                 
                    l /= 90;
                    TimeSpan p = TimeSpan.FromMilliseconds(l);

                    return p;
                }
                else return TimeSpan.Zero;
           }
       }


       public TimeSpan DTS
       {
           get
           {
               if (HasDTS)
               {
                   uint l = 0;
                   byte b1 = (byte)(_packet[PES_OFFSET + 14] & 0xE);
                   byte b2 = (byte)(_packet[PES_OFFSET + 15]);
                   byte b3 = (byte)(_packet[PES_OFFSET + 16] & 0xFE);
                   byte b4 = (byte)(_packet[PES_OFFSET + 17]);
                   byte b5 = (byte)(_packet[PES_OFFSET + 18] & 0xFE);
                   l = (uint) ((b1 << 29) | (b2<<22) | (b3 << 14) | (b4 << 7) | (b5 >> 1));

                   l /= 90;
                   TimeSpan p = TimeSpan.FromMilliseconds(l);
                   return p;
               }
               else return TimeSpan.Zero;
           }
       }


       public int ESSENCE_OFFSET
       {
           get
           {
               return PES_OFFSET + 9 + HEADER_DATA_LENGTH;
           }
       }

        

      }


}
